#pragma once
#include "muduo/proto/codec.h"
#include "muduo/proto/dispatcher.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpClient.h"
#include "consumer.h"
#include "channel.h"
#include "WorkThread.h"
#include <functional>

namespace ns_conn
{
    using namespace ns_channel;
    using namespace ns_consume;
    using namespace ns_work;
    using namespace placeholders;

    class Connection
    {
        typedef std::shared_ptr<google::protobuf::Message> MessagePtr;

    public:
        using ptr = shared_ptr<Connection>;

        Connection(string s_ip, int s_port, const AsyncWorker::ptr &worker)
            : _latch(1), // 只有=1的时候调用wait才会阻塞
              _worker(worker),
              _channels_manager(make_shared<ChannelManage>()),
              _clt(worker->loopthread.startLoop(),
                   muduo::net::InetAddress(s_ip, s_port), "Connection"),
              _dispatcher(std::bind(&Connection::unkonwnmessage, this, _1, _2, _3)),
              _codec(make_shared<ProtobufCodec>(std::bind(
                  &ProtobufDispatcher::onProtobufMessage, &_dispatcher, _1, _2, _3)))
        {
            // 注册_dispatcher业务请求处理函数
            _dispatcher.registerMessageCallback<basicCommonResponse>(
                std::bind(&Connection::basicComm, this, _1, _2, _3));

            _dispatcher.registerMessageCallback<basicConsumeResponse>(
                std::bind(&Connection::basicConsume, this, _1, _2, _3));

            // 连接回调处理
            _clt.setConnectionCallback(std::bind(&Connection::myconnect, this, _1));

            // 设置成协议处理器，在协议处理结束后,其内部会再次调用请求分发器执行对应的回调函数
            _clt.setMessageCallback(std::bind(
                &ProtobufCodec::onMessage, _codec.get(), _1, _2, _3));

            // 连接服务器
            _clt.connect();
            _latch.wait(); // 阻塞等待，直到连接建立成功
        }

        // 对外提供的接口
        Channel::ptr createChannel()
        {
            Channel::ptr cp = _channels_manager->createChannel(_conn, _codec);

            // 2.同步操作(传递信息给服务器)
            cp->createChannel();
            return cp;
        }
        bool closeChannel(Channel::ptr cp)
        {
            // 2.同步操作(传递信息给服务器)
            cp->closeChannel();

            return _channels_manager->closeChannel(cp->getCid());
        }

    private:
        // 基础响应处理
        void basicComm(const muduo::net::TcpConnectionPtr &conn,
                       const basicCommonResponsePtr &message, muduo::Timestamp)
        {
            // 添加进信道的哈希表中(表示对应的请求已经执行完毕)
            Channel::ptr ch = _channels_manager->getChannel(message->cid());
            if (ch.get() == nullptr)
            {
                LOG(WARNING) << "基础响应处理失败，信道不存在" << endl;
                return;
            }
            ch->putBasicRsp(message);
        }

        // 推送响应处理(处理队列消息)
        void basicConsume(const muduo::net::TcpConnectionPtr &conn,
                          const basicConsumeResponsePtr &message, muduo::Timestamp)
        {
            // 调用信道的consumer的回调函数进行处理
            Channel::ptr ch = _channels_manager->getChannel(message->cid());
            if (ch.get() == nullptr)
            {
                LOG(WARNING) << "基础响应处理失败，信道不存在" << endl;
                return;
            }
            // 任务处理采用线程池的方式进行操作
            // _worker->pool.Push([ch, message]()
            //                    { ch->consum(message); });
            _worker->pool.Push(std::bind(&Channel::consum, ch.get(), _1), message);
        }

        // 连接成功建立的回调函数
        void myconnect(const muduo::net::TcpConnectionPtr &conn)
        {
            if (conn->connected())
            {
                _conn = conn;
                _latch.countDown(); // 唤醒
            }
            else
            {
                conn->shutdown();
                cout << "连接关闭" << endl;
            }
        }
        // 收到未知响应后的回调处理函数
        void unkonwnmessage(const muduo::net::TcpConnectionPtr &conn,
                            const MessagePtr &message, muduo::Timestamp)
        {
            LOG_INFO << "未知信息: " << message->GetTypeName();
            conn->shutdown();
        }

    private:
        muduo::CountDownLatch _latch;       // 控制同步（请求连接是异步的）
        muduo::net::TcpClient _clt;         // 用于回调事件就绪后的请求
        muduo::net::TcpConnectionPtr _conn; // 用于数据请求发送
        ProtobufDispatcher _dispatcher;     // 请求分发器-注册请求处理函数
        ProtobufCodecPtr _codec;            // 协议处理器-将收到的请求数据进行协议处理

        ChannelManage::Ptr _channels_manager; // 信道管理
        AsyncWorker::ptr _worker;             // 异步工作线程池(包含以下两个)
        // muduo::net::EventLoopThread loopthread;
        // ThreadPool pool;
    };

}